package schedule;

import java.util.List;
import java.util.Random;

import processes.Process;

public class Scheduler {
	/**
	 * The list of processes.
	 */
	private List<Process> my_procs;

	/**
	 * The type of schedule.
	 */
	private ScheduleType my_type;

	/**
	 * round-robin index.
	 */
	private int index = 0;

	/**
	 * Keeps track of current process.
	 */
	private Process my_process;

	/**
	 * Creates a scheduler with the specified type.
	 * 
	 * @param the_type
	 *            The schedule type.
	 */

	public Scheduler(ScheduleType the_type, List<Process> the_procs) {
		my_type = the_type;
		my_procs = the_procs;
	}

	/**
	 * Returns current stats of system.
	 */
	private String getStats(Process the_curr, Process the_next) {
		StringBuilder sb = new StringBuilder();
		if (the_curr != null && the_next != null) {
			sb.append("Scheduler: Running process ");
			sb.append(my_procs.indexOf(the_curr) + " (");
			sb.append(the_curr.getName());
			// sb.append(the_curr.getClass().getName().replace("processes.",
			// ""));
			sb.append(")\n");
			for (int i = 0; i < my_procs.size(); i++) {
				String status = "";
				if (the_curr == my_procs.get(i))
				{
					status = "RUNNING";
				}
				else if (my_procs.get(i).canRun())
				{
					status = "RUNNABLE";
				}
				else
				{
					status = "BLOCKED";
				}
				sb.append("Process "
						+ i
						+ " ("
						+ my_procs.get(i).getClass().getName()
								.replace("processes.", "") + ")'s state: "
						+ status + "\n");

			}
		}
		return sb.toString();
	}

	private Process getPProc() {
		int max = 0;
		Process rval = null;
		for (Process p : my_procs) {
			if (max < p.my_priority && p.canRun()) {
				max = p.my_priority;
				rval = p;
			}
		}
		my_process = rval;
		return rval;
	}

	private Process getRRProc() {
		index++;
		index = index % my_procs.size();
		while (!(my_procs.get(index).canRun())) {
			index++;
			index = index % my_procs.size();

		}
		Process rval = my_procs.get(index);

		return rval;
	}

	public Process contextSwitch(String reason) {
		Process rval;
		switch (my_type) {
		case ROUND_ROBIN:
			rval = getRRProc();
			break;
		case PRIORITY:
			rval = getPProc();
			break;
		case LOTTERY:
			rval = getLProc();
			break;
		default:
			rval = null;
		}
		System.out.println(getStats(my_process, rval));

		my_process = rval;
		return rval;
	}

	private Process getLProc() {
		Random rand = new Random();
		index = Math.abs(rand.nextInt()) % my_procs.size();
		while (!(my_procs.get(index).canRun())) {
			index = Math.abs(rand.nextInt()) % my_procs.size();
		}
		return my_procs.get(index);
	}
}
